package com.dream.essearch.service.imp;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.dream.essearch.mapper.BookMapper;
import com.dream.essearch.model.dto.BookDTO;
import com.dream.essearch.model.dto.PageResult;
import com.dream.essearch.model.dto.SearchParam;
import com.dream.essearch.model.entity.BookDoc;
import com.dream.essearch.model.entity.BookEntity;
import com.dream.essearch.service.IBookService;
import com.dream.util.IDKit;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description: 图书接口实现类
 * @author: LiMG
 * @create: 2025-04-28 01:02:16
 **/
@Service
public class BookServiceImpl implements IBookService {

    @Autowired
    private BookMapper bookMapper;

    @Autowired
    private RestHighLevelClient client;

    @Override
    public void saveBook(BookDTO bookDTO) {
        BookEntity book = new BookEntity();
        BeanUtils.copyProperties(bookDTO, book);
        book.setId(IDKit.id());
        book.setCreateTime(DateTime.now().toString());
        book.setUpdateTime(DateTime.now().toString());
        bookMapper.insert(book);

        try {
            BookDoc hotelDoc = new BookDoc(book);
            // 1.准备Request
            IndexRequest request = new IndexRequest("book_info").id(hotelDoc.getId().toString());
            // 2.准备请求参数DSL，其实就是文档的JSON字符串
            request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);
            // 3.发送请求
            client.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<BookEntity> getBookList() {
        return bookMapper.selectList(null);
    }

    @Override
    public List<String> getSuggest(String keyword) {
        try {
            // 1. 构建补全查询
            SuggestBuilder suggestBuilder = new SuggestBuilder();
            suggestBuilder.addSuggestion("keyword-suggest",
                    new CompletionSuggestionBuilder("suggestion")
                            .prefix(keyword)
                            .size(5)
            );

            // 2. 创建 SearchRequest
            SearchRequest searchRequest = new SearchRequest("book_info");
            searchRequest.source().suggest(suggestBuilder);

            // 3. 执行查询
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

            // 4. 解析结果并过滤重复项
            return response.getSuggest().getSuggestion("keyword-suggest")
                    .getEntries().stream()
                    .flatMap(entry -> entry.getOptions().stream())
                    .map(option -> option.getText().toString())
                    // 添加 distinct() 方法过滤重复项
                    .distinct() 
                    .collect(Collectors.toList());

        } catch (IOException e) {
            throw new RuntimeException("ES补全查询失败", e);
        }
    }

    @Override
    public PageResult search(SearchParam param) {
        try {
            // 1.准备Request
            SearchRequest request = new SearchRequest("book_info");
            // 2.准备请求参数
            // 2.1.query
            buildBasicQuery(param, request);
            // 2.2.分页
            int page = param.getPageNum();
            int size = param.getPageSize();
            request.source().from((page - 1) * size).size(size);
            // 3.发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            // 4.解析响应
            return handleResponse(response);
        } catch (IOException e) {
            throw new RuntimeException("ES查询失败", e);
        }
    }

    private void buildBasicQuery(SearchParam params, SearchRequest request) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        String key = params.getKeyword();
        if (StringUtils.isNotBlank(key)) {
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        } else {
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        request.source().highlighter(new HighlightBuilder()
                .field("title")
                .field("author")
                .field("publisher").requireFieldMatch(false)).query(boolQuery);
    }

    private PageResult handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        long total = searchHits.getTotalHits().value;
        SearchHit[] hits = searchHits.getHits();
        List<BookDoc> hotels = new ArrayList<>(hits.length);
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString();
            BookDoc bookDoc = JSON.parseObject(json, BookDoc.class);
            Map<String, HighlightField> map = hit.getHighlightFields();
            if (!CollectionUtils.isEmpty(map)) {
                HighlightField titleField = map.get("title");
                if (titleField != null) {
                    String hName = titleField.getFragments()[0].toString();
                    bookDoc.setTitle(hName);
                }
                HighlightField authorField = map.get("author");
                if (authorField != null) {
                    String hName = authorField.getFragments()[0].toString();
                    bookDoc.setAuthor(hName);
                }
                HighlightField publisherField = map.get("publisher");
                if (publisherField != null) {
                    String hName = publisherField.getFragments()[0].toString();
                    bookDoc.setPublisher(hName);
                }
            }
            hotels.add(bookDoc);
        }
        return new PageResult(total, hotels);
    }

}
